﻿namespace DAOGenerator
{
    using System;
    using System.CodeDom;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    public class CodeGenHelper
    {
        private static CodeMemberProperty CreateProperty(string field, string name, Type type, bool isNullable)
        {
            CodeMemberProperty property = new CodeMemberProperty();

            property.Name = name;
            property.Attributes = MemberAttributes.Public;
            property.Type = GetCodeTypeReference(isNullable, type);

            property.SetStatements.Add(
              new CodeAssignStatement(
                new CodeFieldReferenceExpression(null, field),
                    new CodePropertySetValueReferenceExpression()));

            property.GetStatements.Add(
              new CodeMethodReturnStatement(
                new CodeFieldReferenceExpression(null, field)));

            return property;
        }

        private static CodeMemberField CreateField(string type, bool isNullable, string field)
        {
            CodeMemberField cmField = new CodeMemberField(GetCodeTypeReference(isNullable, Type.GetType(type)), field);
            cmField.Attributes = MemberAttributes.Private;
            return cmField;
        }

        private static CodeTypeReference GetCodeTypeReference(bool isNullable, Type type)
        {
            CodeTypeReference ctr;
            if (isNullable)
            {
                ctr = new CodeTypeReference(typeof(Nullable<>));
                ctr.TypeArguments.Add(new CodeTypeReference(type));
            }
            else
            {
                ctr = new CodeTypeReference(type);
            }
            return ctr;
        }

        public static CodeTypeMember[] CreateGetSetMethod(string originalName, string name, string type, bool isNullable)
        {
            var Result = new CodeTypeMember[2];
            string field = string.Format("_{0}", MiscHelper.ReformatFieldString(originalName));
            var ofield = CreateField(type, isNullable, field);
            var oproperty = CreateProperty(field, name, Type.GetType(type), isNullable);

            Result[0] = ofield;
            Result[1] = oproperty;

            return Result;
        }

        public static CodeNamespace CreateNamespace(string namespaceName)
        {
            var ns = new CodeNamespace(namespaceName);

            ns.Comments.Add(new CodeCommentStatement("DAOGenerator =============================================================== DAOGenerator"));
            ns.Comments.Add(new CodeCommentStatement("DAOGenerator ==             THIS CODE IS BEING AUTO GENERATE              == DAOGenerator"));
            ns.Comments.Add(new CodeCommentStatement("DAOGenerator =============================================================== DAOGenerator"));
            ns.Comments.Add(new CodeCommentStatement(string.Format("GENERATED BY : {0}", Environment.MachineName)));
            ns.Comments.Add(new CodeCommentStatement(string.Format("GENERATED AT : {0}", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.ffff"))));
            ns.Comments.Add(new CodeCommentStatement("PLEASE DO NOT MODIFY THIS CODE."));

            return ns;
        }

        public static CodeTypeDeclaration CreateClass(string className, bool isPartial)
        {
            var cls = new CodeTypeDeclaration(className);

            cls.IsClass = true;
            cls.IsPartial = isPartial;

            return cls;
        }

        public static CodeVariableDeclarationStatement CreateVariableDeclaration(string name, Type type)
        {
            CodeVariableDeclarationStatement variableDeclaration = new CodeVariableDeclarationStatement();
            variableDeclaration.Name = name;

            variableDeclaration.Type = new CodeTypeReference(type);

            return variableDeclaration;
        }

        public static CodeMemberField CreateConstantDeclaration(string constantVariableName, object value)
        {
            CodeMemberField codeMemberField = new CodeMemberField(value.GetType(), constantVariableName);
            codeMemberField.Attributes = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | 
                MemberAttributes.Public | MemberAttributes.Const;
            codeMemberField.InitExpression = new CodePrimitiveExpression(value);
            return codeMemberField;
        }

        public static CodeMemberField CreateStaticDeclaration(string constantVariableName, object value)
        {
            CodeMemberField codeMemberField = new CodeMemberField(value.GetType(), constantVariableName);
            codeMemberField.Attributes = (codeMemberField.Attributes & ~MemberAttributes.AccessMask & ~MemberAttributes.ScopeMask) | 
                MemberAttributes.Public | MemberAttributes.Static;
            codeMemberField.InitExpression = new CodePrimitiveExpression(value);
            return codeMemberField;
        }

        public static CodeMemberField CreateClassVariable(Type type, bool isNullable, string variableName)
        {
            CodeMemberField cmField = new CodeMemberField(GetCodeTypeReference(isNullable, type), variableName);
            cmField.Attributes = MemberAttributes.Private;
            return cmField;
        }
    }
}
